#pragma once

#include <string>

#include "Socket.hpp"
#include "agreement.pb.h"

using namespace std;
using namespace SocketModule;

class Expressed  //表示层
{
    static const string default_sep; // 默认分割符

    typedef function<bool(const int, const char, const int, int &)> calc_handle_t; // 计算器

    // 报文格式: 有效载荷长度\r\n有效载荷
    // 缓冲区可能格式：有效载荷长度\r\n有效载荷有效载荷长度\r\n有效载荷有效载荷长度\r...

    bool isFull(string &in, string &sk) // 判断报文是否完整，如果完整就取出一份有效载荷放入sk中
    {
        int pos = in.find(default_sep); // 分割报头和有效载荷

        if (pos == string::npos) // 如果没找到  分割报头和有效载荷的分割符
        {
            return false; // 报头不完整
        }

        // 取出有效载荷的长度
        int pa_size = stoi(in.substr(0, pos));

        // 判断有效载荷是否完整
        if (in.size() - (pos + default_sep.size()) < pa_size)
        {
            return false; // 有效载荷不完整
        }

        // 报文完整，取出有效载荷
        int start = pos + default_sep.size();
        int end = start + pa_size;
        sk = in.substr(start, end); // 取出有效载荷

        // 清除缓冲区中被拿走的报文
        in.erase(0, end);

        return true;
    }

public:
    Expressed()
        :_calc(nullptr)
    {
    }
    void Registration(calc_handle_t calc) // 注册
    {
        _calc = calc;
    }
    string HandleRequest(string &readbuff)
    {
        string sk;             // 一份完整报文
        string outbuf;         //返回值，存放序列化后的响应报文
        while (isFull(readbuff, sk)) // 如果取出一份完整报文
        {
            // 拿到一份有效载荷

            // 解析请求
            Request requ;
            requ.ParseFromString(sk); // 反序列化

            int result = 0;
            bool istrust = false;
            if (_calc != nullptr)
            {
                // 调用计算机注册进来的函数进行计算
                istrust = _calc(requ._left(), (char)requ._operator(), requ._right(), result);
                LOG(LogLevel::DEBUG) << requ._left() << (char)requ._operator() << requ._right()
                                     << "=" << result << ", 结果是否可信：" << istrust;
            }

            // 构建响应
            Response resp;
            resp.set__result(result);
            resp.set__is_trust(istrust);

            // 序列化
            string info;
            resp.SerializeToString(&info);

            // 添加应用层报头:有效载荷长度\r\n
            string out = to_string(info.size()) + "\r\n";
            out += info;

            outbuf += out;

            sk.clear();
        }
        return outbuf;
    }
private:
    calc_handle_t _calc;
};

const string Expressed::default_sep = "\r\n";
